package com.luyou.springframework;

import com.luyou.springframework.annotation.*;
import com.luyou.units.FileUtils;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;

import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 我的appli
 */
public class MyApplicationContext {

    private final Class configClass;

    private final Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();

    private final Map<String, Object> singletonObjects = new HashMap<>();


    public MyApplicationContext(Class configClass) {
        this.configClass = configClass;
        //扫描
        scan(configClass);


        for (String beanName : beanDefinitionMap.keySet()) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            if("singleton".equals(beanDefinition.getScope()) && !beanDefinition.isLazy()){
                Object bean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName, bean);
            }
        }
    }

    /**
     * 创建bean
     * @param beanDefinition
     * @return
     */
    private Object createBean(String beanName, BeanDefinition beanDefinition) {
        Class clazz = beanDefinition.getType();
        try {
            Object o = clazz.newInstance();
            for (Field field  : clazz.getDeclaredFields()) {
                if(field.isAnnotationPresent(Autowired.class)){
                    Object bean = getBean(field.getName());
                    field.setAccessible(true);
                    field.set(o, bean);
                }
            }
            if (o instanceof BeanNameAware) {
                ((BeanNameAware)o).setBeanName(beanName);
            }
            if (o instanceof ApplicationContextAware) {
                ((ApplicationContextAware)o).setApplicationContext(this);
            }
            //是否有事务
            if ( clazz.isAnnotationPresent(Transactional.class)){
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(clazz);
                Object target = o;
                enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
                    System.out.println("事务开启");
                    Object result = method.invoke(target, args);
                    System.out.println("提交事务");
                    return result;
                });
                o = enhancer.create();
            }
            return o;
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 扫描
     * @param configClass
     */
    private void scan(Class configClass) {
        if(configClass.isAnnotationPresent(ComponentScan.class)){
            ComponentScan componentScan = (ComponentScan)configClass.getAnnotation(ComponentScan.class);
            //获取扫描包的路径
            String path = componentScan.value();
            path = path.replace(".", "/");
//            System.out.println(path);
            //获取当前类加载器
            ClassLoader classLoader = this.getClass().getClassLoader();
            URL resource = classLoader.getResource(path);
            if(resource == null){
                System.out.println("未获取到需要加载的springBean");
                return;
            }
            List<File> loadClassFile = FileUtils.findLoadClassFile(resource.getPath(),  "class");
            if(loadClassFile == null){
                System.out.println("未获取到需要加载的springBean");
                return;
            }
            List<String> classNameList = loadClassFile.stream()
                    .map(file -> {
                        String absolutePath = file.getAbsolutePath();
                        absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"))
                                .replace("\\", ".");
                        return absolutePath;
                    })
                    .collect(Collectors.toList());
            for (String className : classNameList) {
                try {
                    //加载类
                    Class<?> clazz = classLoader.loadClass(className);
                    if(clazz.isAnnotationPresent(Component.class)){
                        BeanDefinition beanDefinition = new BeanDefinition();
                        beanDefinition.setType(clazz);
                        beanDefinition.setLazy(clazz.isAnnotationPresent(Lazy.class));
                        if(clazz.isAnnotationPresent(Scope.class)){
                            beanDefinition.setScope(clazz.getAnnotation(Scope.class).value());
                        }else {
                            beanDefinition.setScope("singleton");
                        }

                        String beanName = clazz.getAnnotation(Component.class).value();
                        if(beanName.isEmpty()){
                            beanName = Introspector.decapitalize(clazz.getSimpleName());
                        }
                        //存入bean
                        beanDefinitionMap.put(beanName, beanDefinition);
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 通过名字获取bean
     * @param beanName
     * @return
     */
    public Object getBean(String beanName) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition == null) {
            throw new NullPointerException();
        }
        if ("singleton".equals(beanDefinition.getScope())) {
            Object result = singletonObjects.get(beanName);
            if (result == null) {
                result = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName, result);
            }
            return result;
        }else {
            return createBean(beanName, beanDefinition);
        }
    }
}
